﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LightPersist.Exceptions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestDomainModel;

namespace LightPersistTests
{
	[TestClass]
	public class PropertyOfObjectTypeManagement : TripleTestsBase
	{
		FakeUntypedManager mgr;

		[TestInitialize]
		public void init()
		{
			mgr = Context.Create<FakeUntypedManager>();
			Root.UntypedManager = mgr;
		}

		void DoReconnect()
		{
			Reconnect();
			init_();
		}

		void DoChangeContext()
		{
			ChangeContext();
			init_();
		}

		void init_()
		{
			mgr = Context.GetObjectByID<FakeUntypedManager>(mgr.ID);
			child = Context.GetObjectByID<FakeControl>(child.ID);
		}

		[TestMethod]
		public void Should_allow_set_model_to_object_property()
		{
			var newModel = Context.Create<FakeControl>();
			newModel.Name = Guid.NewGuid().ToString();
			mgr.SomeObject = newModel;

			DoReconnect();

			var test = (FakeControl)mgr.SomeObject;

			Assert.AreEqual(newModel.ID, test.ID);
			Assert.AreEqual(newModel.Name, test.Name);
			Assert.IsTrue(test.BackReferences.Contains(mgr));

			// obj exists
			NotThrows(() => Context.GetObjectByID(newModel.ID));

			var newModel2 = Context.Create<FakeControl>();
			mgr.SomeObject = newModel2;

			DoReconnect();

			// obj not exists
			Throws(() => Context.GetObjectByID(newModel.ID));
			//NotThrows(() => Context.GetObjectByID(newModel2.ID));

			mgr.SomeObject = null;

			DoReconnect();

			// obj not exists
			Throws(() => Context.GetObjectByID(newModel.ID));
			Throws(() => Context.GetObjectByID(newModel2.ID));
		}

		[TestMethod]
		public void Should_allow_set_int_to_object_property()
		{
			mgr.SomeObject = 123;
			DoReconnect();
			var test = (int)mgr.SomeObject;
			Assert.AreEqual(123, test);
		}

		[TestMethod]
		public void Should_allow_set_int_to_object_primitiveonly_property()
		{
			mgr.SomeObjectPrimitiveOnly = 123;
			DoReconnect();
			var test = (int)mgr.SomeObjectPrimitiveOnly;
			Assert.AreEqual(123, test);
		}

		[TestMethod]
		public void Should_not_allow_use_untyped_primitive_property_for_model()
		{
			Throws<LightPersistException>(delegate
			{
				mgr.SomeObjectPrimitiveOnly = child;
			});
		}

		[TestMethod]
		public void Should_allow_call_object_with_small_letter()
		{
			mgr.SomeObject3 = child;
		}

		[TestMethod]
		public void Should_allow_works_with_ifaces()
		{
			mgr.SomeIface = 4;

			//mgr.SomeIface = child;
			Assert.Inconclusive();
		}

		[TestMethod]
		public void Should_allow_replace_model_to_int_with_integrity_checking()
		{
			// Todo когда сдесь был new model, тест не проходил, т.к. при удалении поднимался еще раз новый инстанс объекта из стореджа и бек референсы обновлялись у него (очищались), а при последующей попытке засунуть newModel в базу, действие Create не добавлялось, т.к. у объекта были бэк референсы. Это нужно учесть и защититься от этого.
			//var newModel = Context.Create<FakeControl>();

			child.Name = Guid.NewGuid().ToString();
			mgr.SomeObject = child;

			DoReconnect();

			mgr.SomeObject = 15;

			DoReconnect();

			Assert.AreEqual(15, mgr.SomeObject);

			mgr.SomeObject = child;

			DoReconnect();

			Assert.AreEqual(child, mgr.SomeObject);
		}

		[TestMethod]
		public void Should_allow_use_heterogeneous_collection_with_checking_consistancy()
		{
			mgr.SomeListOfObject.Add(child);
			mgr.SomeListOfObject.Add(Context.Create<FakeAnimation>());

			DoReconnect();

			Assert.AreEqual(2, mgr.SomeListOfObject.Count);
			var test = (FakeControl)mgr.SomeListOfObject.First();

			Assert.AreEqual(child.ID, test.ID);
			Assert.AreEqual(child.Name, test.Name);
			Assert.IsTrue(test.BackReferences.Contains(mgr));

			mgr.SomeListOfObject.Remove(child);

			DoReconnect();

			Assert.AreEqual(1, mgr.SomeListOfObject.Count);
			Assert.IsFalse(child.BackReferences.Contains(mgr));
		}


	}
}
